package gopi.labs.database;

import gopi.labs.Connector.NameValue;
import gopi.labs.exceptions.InValidIdentifier;
import gopi.labs.exceptions.InvalidDataRecord;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.UUID;

public abstract class Database {
	protected Properties properties;
	protected Connection connection;
	protected String name;
	private String password;
	protected UUID id;
	private List<NameValue> attributes;

	public abstract List<NameValue> getAttributeDetails() throws SQLException,
			InvalidDataRecord;

	public abstract void insertUpdateAttributes(List<NameValue> attributes)
			throws SQLException;

	private void init() {
		attributes = new ArrayList<NameValue>();
	}

	public Database(String name) {
		this.name = name.toUpperCase();
		this.id = UUID.randomUUID();
		init();
	}

	public void connect() throws SQLException, ClassNotFoundException {

		Class.forName(this.properties.getProperty("HSQLDB_CLASS"));

		this.connection = DriverManager.getConnection(
				this.properties.getProperty("HSQLDB_URL"),
				this.properties.getProperty("HSQLDB_USER"),
				this.properties.getProperty("HSQLDB_PASSWORD"));
		
		this.connection.setAutoCommit(false);
	}

	public void disconnect() throws SQLException {
		this.connection.close();
	}
	public boolean checkCloudExists(String name) throws SQLException {
		Statement stmt = this.connection.createStatement();

		ResultSet rs = stmt
				.executeQuery("select count(*) from metadata.cloud where name = '"
						+ name + "'");
		if (rs.next() && rs.getInt(1) == 0) {
			rs.close();
			stmt.close();
			return false;
		}
		rs.close();
		stmt.close();
		return true;
	}
	public boolean checkDataModelExists(String dataModel, String cloudSpace) throws SQLException {
		Statement stmt = this.connection.createStatement();

		ResultSet rs = stmt
				.executeQuery("select count(*) from metadata.data_model where name = '"
						+ dataModel
						+ "' and cloud_name = '"
						+ cloudSpace + "'");
		if (rs.next() && rs.getInt(1) == 0) {
			rs.close();
			stmt.close();
			return false;
		}
		rs.close();
		stmt.close();
		return true;
	}
	

	public void validate() throws InValidIdentifier, SQLException {
		if (!properties.containsKey("HSQLDB_CLASS")
				|| (properties.containsKey("HSQLDB_CLASS") && (properties
						.getProperty("HSQLDB_CLASS") == null || properties
						.get("HSQLDB_CLASS").toString().equalsIgnoreCase("")))) {
			throw new InValidIdentifier(
					"HSQLDB_CLASS is not available in config file");
		}
		if (!properties.containsKey("HSQLDB_URL")
				|| (properties.containsKey("HSQLDB_URL") && (properties
						.getProperty("HSQLDB_URL") == null || properties
						.get("HSQLDB_URL").toString().equalsIgnoreCase("")))) {
			throw new InValidIdentifier(
					"HSQLDB_URL is not available in config file");
		}
		if (!properties.containsKey("HSQLDB_USER")
				|| (properties.containsKey("HSQLDB_USER") && (properties
						.getProperty("HSQLDB_USER") == null || properties
						.get("HSQLDB_USER").toString().equalsIgnoreCase("")))) {
			throw new InValidIdentifier(
					"HSQLDB_USER is not available in config file");
		}
		if (!properties.containsKey("HSQLDB_PASSWORD")
				|| (properties.containsKey("HSQLDB_PASSWORD") && (properties
						.getProperty("HSQLDB_PASSWORD") == null || properties
						.get("HSQLDB_PASSWORD").toString().equalsIgnoreCase("")))) {
			throw new InValidIdentifier(
					"HSQLDB_PASSWORD is not available in config file");
		}
		if (this.getName() == null || this.getName().equalsIgnoreCase("")) {
			throw new InValidIdentifier("Identifier Name is not set or null");
		}

	}

	public void readParams() throws IOException {
		this.properties = new Properties();
		InputStream is = new FileInputStream("config.properties");
		properties.load(is);

	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name.toUpperCase();
	}

	public UUID getId() {
		return id;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public void addAttribute(Object name, Object value) {
		this.attributes.add(new NameValue(name, value));
	}

	public List<NameValue> getAttributes() {
		return this.attributes;
	}
}
